/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */

#include <stdlib.h>

// Declares clang::SyntaxOnlyAction.
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
// Declares llvm::cl::extrahelp.
#include "Clang2MapleOptions.h"
#include "llvm/Support/CommandLine.h"

#include "Clang2MapleVisitor.h"

#ifndef MAPLE_ROOT
#error "MAPLE_ROOT must be defined"
#endif
#ifndef INSTALL_DIR
#define INSTALL_DIR "/usr/local"
#endif

using namespace clang::tooling;
using namespace llvm;

static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::OptionCategory Clang2MapleCategory("clang2mpl options");

cl::opt<bool> UseAscii(
    "ascii",
    cl::desc(
        R"(Generate ASCII maple. If not set, binary maple will be generated
by default.)"),
    cl::init(false), cl::cat(Clang2MapleCategory));
cl::opt<bool> VerifyMaple("verify",
                          cl::desc(R"(Verify the generated Maple IR.)"),
                          cl::init(false), cl::cat(Clang2MapleCategory));
cl::opt<bool> SimpleShortCircuit(
    "simple-short-circuit",
    cl::desc(
        R"(Expand short-circuit and/or expressions when there are no side-effects in the RHS.)"),
    cl::init(true), cl::cat(Clang2MapleCategory));
cl::opt<bool> NoSimpleShortCircuit(
    "no-simple-short-circuit",
    cl::desc(
        R"(Do not expand short-circuit and/or expressions when there are no side-effects in the RHS.)"),
    cl::init(false), cl::cat(Clang2MapleCategory));
cl::opt<bool> ImprovedIsSimple(
    "improved-issimple",
    cl::desc(
        R"(Use the improved check for whether an expression is "simple".)"),
    cl::init(true), cl::cat(Clang2MapleCategory));
cl::opt<bool> NoImprovedIsSimple(
    "no-improved-issimple",
    cl::desc(
        R"(Do not use the improved check for whether an expression is "simple".)"),
    cl::init(false), cl::cat(Clang2MapleCategory));

// A help message for this specific tool can be added afterwards.
static cl::extrahelp MoreHelp("\nMore help text...\n");

int main(int argc, const char **argv) {
  // Set environment variable to ensure proper include directories are used
  // during compilation
  setenv("C_INCLUDE_PATH",
         MAPLE_ROOT "/tools/sysroot-glibc-linaro-2.25/usr/include:" INSTALL_DIR
                    "/lib/clang2mpl/include:" MAPLE_ROOT
                    "/tools/clang+llvm-12.0.0-x86_64-linux-gnu-ubuntu-18.04/"
                    "lib/clang/12.0.1/include",
         1);

  auto ExpectedParser = CommonOptionsParser::create(
      argc, argv, Clang2MapleCategory, llvm::cl::OneOrMore);
  if (!ExpectedParser) {
    llvm::errs() << ExpectedParser.takeError();
    return 1;
  }
  CommonOptionsParser &OptionsParser = ExpectedParser.get();
  ClangTool Tool(OptionsParser.getCompilations(),
                 OptionsParser.getSourcePathList());
  maple::Triple::GetTriple().Init();
  return Tool.run(clang2MapleFrontendActionFactory().get());
}
